package com.jy.modules.cims.interact;

import java.net.SocketTimeoutException;
import java.sql.Timestamp;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import com.fasterxml.jackson.core.type.TypeReference;
import com.jy.modules.cims.common.CimsConstant;
import com.jy.modules.cims.common.CimsIrtUrlConstant;
import com.jy.modules.cims.common.exception.CimsException;
import com.jy.modules.cims.common.exception.CimsExceptionConstant;
import com.jy.modules.cims.common.exception.InteractException;
import com.jy.modules.cims.common.sysUtils.LoggerUtils;
import com.jy.modules.cims.common.sysUtils.PropertyUtil;
import com.jy.modules.cims.data.common.dao.TCMmDealInterfaceDao;
import com.jy.modules.cims.data.dao.SysAssistDao;
import com.jy.modules.cims.data.dto.InteractEnsureDto;
import com.jy.modules.cims.data.interact.core.BaseHeaderRequestDTO;
import com.jy.modules.cims.data.interact.core.BaseHeaderResponseDTO;
import com.jy.platform.core.message.ResponseMsg;
import com.jy.platform.core.message.ResponseStatus;
import com.jy.platform.restclient.http.RestClient;
import com.jy.platform.restclient.http.RestService;
import com.jy.platform.tools.common.JacksonMapper;

/**
 * 系统间交互统一客户端
 */
@Service("com.jy.modules.cims.interact.InteractClient")
public class InteractClient {

	private static final Logger logger = LoggerFactory.getLogger(InteractClient.class);

	// @Autowired
	// @Qualifier("com.jy.modules.cims.core.service.sysAssist.CSysAssistImpl")
	// public ICSysAssist iCSysAssist;

	private int intervalTimes = 2;

	@Autowired
	@Qualifier("com.jy.modules.cims.interact.CInteractAssist")
	public IInteractAssist iInteractAssist;

	@Autowired
	public SysAssistDao sysAssistDao;

	@Autowired
	public TCMmDealInterfaceDao tcmmDealInterfaceDao;
	/**核心系统rest服务appId*/
	private static String coreAppId = PropertyUtil.get(CimsConstant.SYSID_CORE); 
	/**核心系统rest服务地址*/
	private static String coreURL = RestService.getServiceUrl(coreAppId);
	/**贷前系统rest服务appId*/ 
	private static String befloanAppId = PropertyUtil.get(CimsConstant.SYSID_BEFLOAN); 
	/**贷前系统rest服务地址 COLLATERAL*/ 
	private static String befloanURL = RestService.getServiceUrl(befloanAppId);
	/**抵押品系统rest服务appId*/ 
	private static String collateralAppId = PropertyUtil.get(CimsConstant.SYSID_COLLATERAL); 
	/**抵押品系统rest服务地址 COLLATERAL*/ 
	private static String collateralURL = RestService.getServiceUrl(collateralAppId);
	/**主数据系统rest服务appId*/ 
	private static String masterdataAppId = PropertyUtil.get(CimsConstant.SYSID_MASTERDATA);
	/** 主数据系统rest服务地址  COLLATERAL*/
	private static String masterdataURL = RestService.getServiceUrl(masterdataAppId);

	// long interval =
	// Long.parseLong(PropertyUtil.get(CimsConstant.INTERACT_INTERVAL));

	/**
	 * 与核心系统交互。 与核心系统的所有交互接口统一调用该方法。<br/>
	 * 注：参数中的泛型T为交互接口返回值，此方法默认T类型都继承了BaseHeaderResponseDTO类。
	 * 
	 * @param url 接口地址
	 * @param data 请求数据
	 * @param typeReference 返回数据的载体
	 * @param ensureDto 接口异常处理实体
	 * @return T 返回数据
	 * @author chenguixue
	 * @date 2015-1-21-下午5:12:14
	 * @update
	 */
	public <T, D> T sendReqToCore(String url, D data, TypeReference<ResponseMsg<T>> typeReference, InteractEnsureDto ensureDto) {
		// return this.sendReqToSys(url, data, typeReference, ensureDto,
		// CimsIrtUrlConstant.IRT_SYSSOURCE);
		return this.sendReqToCoreBak(url, data, typeReference, ensureDto, CimsIrtUrlConstant.IRT_SYSSOURCE);
	}

	public <T, D> T sendReqToBefLoan(String url, D data, TypeReference<ResponseMsg<T>> typeReference, InteractEnsureDto ensureDto) {
		// return this.sendReqToSys(url, data, typeReference, ensureDto,
		// CimsIrtUrlConstant.IRT_SYSSOURCE);
		return this.sendReqToCoreBak(url, data, typeReference, ensureDto, CimsIrtUrlConstant.IRT_SYSSOURCE_BEFLOAN);
	}

	public <T, D> T sendReqToCollateral(String url, D data, TypeReference<ResponseMsg<T>> typeReference, InteractEnsureDto ensureDto) {
		// return this.sendReqToSys(url, data, typeReference, ensureDto,
		// CimsIrtUrlConstant.IRT_SYSSOURCE);
		return this.sendReqToCoreBak(url, data, typeReference, ensureDto, CimsIrtUrlConstant.IRT_SYSSOURCE_COLLATERAL);
	}

	public <T, D> T sendReqToMasterdata(String url, D data, TypeReference<ResponseMsg<T>> typeReference, InteractEnsureDto ensureDto) {
		// return this.sendReqToSys(url, data, typeReference, ensureDto,
		// CimsIrtUrlConstant.IRT_SYSSOURCE);
		return this.sendReqToCoreBak(url, data, typeReference, ensureDto, CimsIrtUrlConstant.IRT_SYSSOURCE_MASTERDATA);
	}

	// /**
	// * 与核心系统交互。 与核心系统的所有交互接口统一调用该方法。<br/>
	// * 注：参数中的泛型T为交互接口返回值，此方法默认T类型都继承了BaseHeaderResponseDTO类。
	// *
	// * @param url 接口地址
	// * @param data 请求数据
	// * @param typeReference 返回数据的载体
	// * @param ensureDto 接口异常处理实体
	// * @return T 返回数据
	// * @author chenguixue
	// * @date 2015-1-21-下午5:12:14
	// * @update
	// */
	// public <T, D> T sendReqToSys(String url, D data,
	// TypeReference<ResponseMsg<T>> typeReference,
	// InteractEnsureDto ensureDto, String sysSource) {
	// ResponseMsg<T> result = null;
	// T bady = null;
	// BaseHeaderResponseDTO headerResp = null;
	// BaseHeaderRequestDTO headerReq = null;
	// try {
	// // 根据交易流水号获得接口流水号，并设置到接口请求中
	// headerReq = (BaseHeaderRequestDTO) data;
	// DealInterfaceDto searchDto = new DealInterfaceDto();
	// String interfaceNo = headerReq.getInterfaceNo();
	// String isQuery =
	// CimsIrtUrlConstant.interactCfg.get(interfaceNo).get(CimsIrtUrlConstant.IS_QUERY)
	// == null ? CimsIrtUrlConstant.IS_QUERY_N
	// : CimsIrtUrlConstant.IS_QUERY_Y;
	// DealInterfaceDto curDealInterfaceDto = null; // 本次交互使用的记录
	// List<DealInterfaceDto> didList = null;
	// if (CimsIrtUrlConstant.IS_QUERY_N.equals(isQuery)) {
	// searchDto.setDealCode(ensureDto.getDealCode());
	// didList =
	// sysAssistDao.getInterfaceCodeByDealCode(SearchParamUtil.getSearchParam(searchDto));
	// for (DealInterfaceDto dto : didList) {
	// if (CimsConstant.INTERACT_IMPL_FALSE.equals(dto.getStatus())) {
	// curDealInterfaceDto = dto;
	// break;
	// }
	// }
	// if (curDealInterfaceDto == null) {
	// logger.info(CimsExceptionConstant.INTERACT_RESTCLIENT_SERVICE_FAIL);
	// throw new
	// InteractException(CimsExceptionConstant.INTERACT_GET_INTERACTNO_FAIL);
	// }
	// headerReq.setFrontTransNo(curDealInterfaceDto.getFronttransno()); //
	// 接口流水号
	// } else {
	// // 查询类型接口调用，不需要校验交易流水号
	// String busiNoForInteract = iInteractAssist.getInteractNo();
	// headerReq.setFrontTransNo(busiNoForInteract); // 接口流水号
	// ensureDto.setDealCode(busiNoForInteract);
	// }
	// headerReq.setSysSource(sysSource); // 系统来源
	// headerReq.setFrontTransTime(new Timestamp(System.currentTimeMillis()));
	// // 交互事件
	// logger.info(LoggerUtils.getLogToDbInfo("request " +
	// JacksonMapper.getInstance().writeValueAsString(data)));
	// // 保存交互日志,交互时间，交互请求参数 待完善
	// if (CimsIrtUrlConstant.IRT_SYSSOURCE.equals(sysSource)) {
	// result = RestClient.doPost(coreAppId, coreURL + url, data,
	// typeReference);
	// } else if (CimsIrtUrlConstant.IRT_SYSSOURCE_BEFLOAN.equals(sysSource)) {
	// result = RestClient.doPost(befloanAppId, befloanURL + url, data,
	// typeReference);
	// }
	// if (result != null) {
	// logger.info(LoggerUtils.getLogToDbInfo("response "
	// + JacksonMapper.getInstance().writeValueAsString(result)));
	// bady = result.getResponseBody();
	// if (bady != null) {
	// headerResp = (BaseHeaderResponseDTO) bady;
	// if (CimsIrtUrlConstant.IS_QUERY_N.equals(isQuery)) {
	// if (!"0000".equals(headerResp.getRetCode()) && null !=
	// headerResp.getRetCode()) { // 业务处理失败
	// if (ensureDto != null) { // 不做接口异常机制处理
	// logger.error(CimsExceptionConstant.INTERACT_SERVICE_BUSI_FAIL,
	// ensureDto.getDealCode(),
	// headerResp.getFrontTransNo(), headerResp.getRetMsg());
	// // 将本次交易流水调用记录备份，需完善
	//
	// // 将已完成调用的接口流水号执行状态重置，以便下次重复调用
	// for (DealInterfaceDto dto : didList) {
	// if (CimsConstant.INTERACT_IMPL_TRUE.equals(dto.getStatus())) {
	// dto.setStatus(CimsConstant.INTERACT_IMPL_FALSE);
	// tcmmDealInterfaceDao.updateTCMmDealInterface(SearchParamUtil
	// .getSearchParam(dto));
	// }
	// }
	// curDealInterfaceDto.setStatus(CimsConstant.INTERACT_IMPL_FALSE);
	// curDealInterfaceDto.setFronttransno(iInteractAssist.getInteractNo()); //
	// 更新本次接口流水号,以便下次交互重新调用
	// tcmmDealInterfaceDao.updateTCMmDealInterface(SearchParamUtil
	// .getSearchParam(curDealInterfaceDto));
	// }
	// bady = null;
	// throw new InteractException(CimsExceptionConstant.INTERACT_SERVICE_FAIL
	// + headerResp.getRetMsg());
	// } else { // 业务处理成功
	// // 将本次接口执行状态置已完成状态,以便下一个接口获取到正确的接口流水号
	// curDealInterfaceDto.setStatus(CimsConstant.INTERACT_IMPL_TRUE);
	// tcmmDealInterfaceDao.updateTCMmDealInterface(SearchParamUtil
	// .getSearchParam(curDealInterfaceDto));
	// }
	// } else {
	// if (!"0000".equals(headerResp.getRetCode()) && null !=
	// headerResp.getRetCode()) {
	// bady = null;
	// throw new InteractException(CimsExceptionConstant.INTERACT_SERVICE_FAIL
	// + headerResp.getRetMsg());
	// }
	// }
	// } else { // 如果是超时，404等异常时,抛出异常，终止事务
	// if (ResponseStatus.HTTP_NOT_FOUND.equals(result.getRetCode())) {
	// throw new
	// InteractException(CimsExceptionConstant.INTERACT_SERVICE_NOTFOUND
	// + result.getErrorDesc());
	// }
	// if (ResponseStatus.HTTP_SERVER_ERROR.equals(result.getRetCode())) {
	// throw new
	// InteractException(CimsExceptionConstant.INTERACT_SERVICE_NOTFOUND
	// + result.getErrorDesc());
	// }
	// throw new InteractException(CimsExceptionConstant.INTERACT_NETWORK_ERROR
	// + result.getErrorDesc());
	//
	// }
	// } else {
	// // 核心服务异常时，返回result为null，认为核心超时
	// throw new
	// InteractException(CimsExceptionConstant.INTERACT_NETWORK_ERROR);
	// }
	// }
	// catch (RestException e) {
	// bady = null;
	// e.printStackTrace();
	// logger.error(CimsExceptionConstant.INTERACT_RESTCLIENT_SERVICE_FAIL, e);
	// throw new
	// InteractException(CimsExceptionConstant.INTERACT_RESTCLIENT_SERVICE_FAIL
	// + ":"
	// + (result == null ? "" : result.getErrorDesc()));
	// }
	// catch (Exception e) {
	// bady = null;
	// e.printStackTrace();
	// logger.error(CimsExceptionConstant.INTERACT_SERVICE_FAIL, e);//
	// result.getErrorDesc()
	// throw new InteractException(CimsExceptionConstant.INTERACT_SERVICE_FAIL +
	// ":"
	// + (result == null ? "" : result.getErrorDesc()));
	// }
	// return bady;
	// }

	/**
	 * 根据交易流水号获得接口流水号<br/>
	 * 单笔交易流水号可能对应多笔接口流水号，根据时间倒排序，取第一条接口返回
	 * 
	 * @param dealCode 交易流水号
	 * @return String 交易对应的接口流水号
	 * @author chenguixue
	 * @date 2015-1-26-下午5:20:40
	 * @update
	 */
	
	/*public String getInterfaceCodeByDealCode(String dealCode) {
		Map<String, Object> searchParams = new HashMap<String, Object>();
		DealInterfaceDto dto = new DealInterfaceDto();
		dto.setDealCode(dealCode);
		searchParams.put("dto", dto);
		List<DealInterfaceDto> list = sysAssistDao.getInterfaceCodeByDealCode(searchParams);
		if (list != null && list.size() > 0) {
			return list.get(0).getFronttransno();
		}
		return null;
	}*/
	 

	/**
	 * 与核心系统交互。 与核心系统的所有交互接口统一调用该方法。<br/>
	 * 注：参数中的泛型T为交互接口返回值，此方法默认T类型都继承了BaseHeaderResponseDTO类。
	 * 
	 * @param url
	 *            接口地址
	 * @param data
	 *            请求数据
	 * @param typeReference
	 *            返回数据的载体
	 * @param ensureDto
	 *            接口异常处理实体
	 * @return T 返回数据
	 * @author chenguixue
	 * @date 2015-1-21-下午5:12:14
	 * @update
	 */
	private <T, D> T sendReqToSysBak(String url, D data, TypeReference<ResponseMsg<T>> typeReference, InteractEnsureDto ensureDto, String sysSource) {
		ResponseMsg<T> result = null;
		T bady = null;
		BaseHeaderResponseDTO headerResp = null;
		BaseHeaderRequestDTO headerReq = null;
		try {
			// 根据交易流水号获得接口流水号，并设置到接口请求中
			headerReq = (BaseHeaderRequestDTO) data;
			if (StringUtils.isEmpty(headerReq.getFrontTransNo())) {
				String busiNoForInteract = iInteractAssist.getInteractNo();
				headerReq.setFrontTransNo(busiNoForInteract); // 接口流水号
			}
			headerReq.setSysSource(sysSource); // 系统来源
			headerReq.setFrontTransTime(new Timestamp(System.currentTimeMillis())); // 交互事件
			logger.info(LoggerUtils.getLogToDbInfo("request " + JacksonMapper.getInstance().writeValueAsString(data)));
			// 保存交互日志,交互时间，交互请求参数 待完善
			if (CimsIrtUrlConstant.IRT_SYSSOURCE.equals(sysSource)) {
				result = RestClient.doPost(coreAppId, coreURL + url, data, typeReference);
			} else if (CimsIrtUrlConstant.IRT_SYSSOURCE_BEFLOAN.equals(sysSource)) {
				result = RestClient.doPost(befloanAppId, befloanURL + url, data, typeReference);
			} else if (CimsIrtUrlConstant.IRT_SYSSOURCE_COLLATERAL.equals(sysSource)) {
				result = RestClient.doPost(collateralAppId, collateralURL + url, data, typeReference);
			} else if (CimsIrtUrlConstant.IRT_SYSSOURCE_MASTERDATA.equals(sysSource)) {
				result = RestClient.doPost(masterdataAppId, masterdataURL + url, data, typeReference);
			}

			if (result != null) {
				logger.info(LoggerUtils.getLogToDbInfo("response " + JacksonMapper.getInstance().writeValueAsString(result)));
				if (CimsIrtUrlConstant.IRT_SYSSOURCE.equals(sysSource)) {
					bady = result.getResponseBody();
					if (bady != null) {
						headerResp = (BaseHeaderResponseDTO) bady;
						if ("业务处理中".equals(headerResp.getRetMsg())) { // 业务处理中
							if (ensureDto != null) { // 不做接口异常机制处理
								logger.error(CimsExceptionConstant.INTERACT_SERVICE_BUSI_FAIL, ensureDto.getDealCode(), headerResp.getFrontTransNo(), headerResp.getRetMsg());
							}
							bady = null;
							throw new InteractException(CimsExceptionConstant.INTERACT_SERVICE_FAIL + headerResp.getRetMsg());
						}
						if (!"0000".equals(headerResp.getRetCode())) { // 业务处理失败
							if (ensureDto != null) { // 不做接口异常机制处理
								logger.error(CimsExceptionConstant.INTERACT_SERVICE_BUSI_FAIL, ensureDto.getDealCode(), headerResp.getFrontTransNo(), headerResp.getRetMsg());
							}
							bady = null;
							throw new CimsException(CimsExceptionConstant.INTERACT_SERVICE_FAIL + headerResp.getRetMsg());
						}
					} else { // 如果是超时，404等异常时,抛出异常，终止事务
						if (ResponseStatus.HTTP_NOT_FOUND.equals(result.getRetCode())) {
							throw new InteractException(CimsExceptionConstant.INTERACT_SERVICE_NOTFOUND + result.getErrorDesc());
						}
						if (ResponseStatus.HTTP_SERVER_ERROR.equals(result.getRetCode())) {
							throw new InteractException(CimsExceptionConstant.INTERACT_SERVICE_NOTFOUND + result.getErrorDesc());
						}
						throw new InteractException(CimsExceptionConstant.INTERACT_NETWORK_ERROR + result.getErrorDesc());

					}
				} else if (CimsIrtUrlConstant.IRT_SYSSOURCE_BEFLOAN.equals(sysSource) || CimsIrtUrlConstant.IRT_SYSSOURCE_COLLATERAL.equals(sysSource)
						|| CimsIrtUrlConstant.IRT_SYSSOURCE_MASTERDATA.equals(sysSource)) {
					if ("200".equals(result.getRetCode())) {
						bady = result.getResponseBody();
						if (bady != null)
							return result.getResponseBody();
						else
							throw new InteractException(CimsExceptionConstant.INTERACT_NETWORK_ERROR + result.getErrorDesc());
					} else {
						throw new InteractException(CimsExceptionConstant.INTERACT_NETWORK_ERROR + result.getErrorDesc());
					}
				}
			} else {
				// 核心服务异常时，返回result为null，认为核心超时
				throw new InteractException(CimsExceptionConstant.INTERACT_NETWORK_ERROR);
			}
		} catch (Exception e) {
			bady = null;
			logger.error(e.getMessage(), e);
			if (e instanceof SocketTimeoutException) {// e instanceof
														// ConnectTimeoutException
				throw new InteractException(CimsExceptionConstant.INTERACT_NETWORK_ERROR);
			}
			throw e;
		}
		return bady;
	}

	private <T, D> T sendReqToCoreInterval(int currentTime, String url, D data, TypeReference<ResponseMsg<T>> typeReference, InteractEnsureDto ensureDto, String source) {

		T bady = null;
		try {
			bady = this.sendReqToSysBak(url, data, typeReference, ensureDto, source);
		} catch (Exception e) {
			if (e instanceof CimsException) {
				throw e;
			} else {
				long millis = 500;
				if (data instanceof BaseHeaderRequestDTO) {
					String interfaceNo = ((BaseHeaderRequestDTO) data).getInterfaceNo();
					if (CimsIrtUrlConstant.IRT_CREDIT_TWO_BUY_TO_CORE.equals(interfaceNo)) {
						millis = 1000 * 60 * 3;
					} else if (CimsIrtUrlConstant.IRT_CREDIT_APPROVE.equals(interfaceNo) || CimsIrtUrlConstant.IRT_SEND_SRCREDIT_TO_CORE.equals(interfaceNo)
							|| CimsIrtUrlConstant.IRT_CREDIT_REDEEM.equals(interfaceNo) || CimsIrtUrlConstant.IRT_SRCREDIT_TRANSFER_REDEEM_TO_CORE.equals(interfaceNo)) {
						millis = 1000 * 60 * 2;
					}
				}
				try {
					Thread.sleep(millis);
				} catch (InterruptedException e1) {
					e1.printStackTrace();
				}

				if (currentTime < intervalTimes) {
					sendReqToCoreInterval(++currentTime, url, data, typeReference, ensureDto, source);
				} else {
					throw new InteractException(e.getMessage());
				}
			}
		}
		return bady;
	}

	private <T, D> T sendReqToCoreBak(String url, D data, TypeReference<ResponseMsg<T>> typeReference, InteractEnsureDto ensureDto, String source) {
		return sendReqToCoreInterval(0, url, data, typeReference, ensureDto, source);
	}

}
